home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Almathera Ten Pack 3: CDPD 3
/
Almathera Ten on Ten - Disc 3: CDPD3.iso
/
scope
/
076-100
/
scopedisk81
/
wkeys
/
bindwkeys.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-03-19
|
24KB
|
846 lines
/*
* BindWKeys.c Reads a file and creates an array of key bindings
* to be used by a hot-key handler to tell which keys
* do what.
*
* Copyright (c) 1987,1988 by Davide P. Cervone
* You may use this code provided this copyright notice is left intact.
*/
#include <exec/types.h>
#include <exec/memory.h>
#include <devices/inputevent.h>
#ifndef NO_FILE
#include <stdio.h>
#endif
#include "wKeys.h"
#ifndef NO_FILE
#define KEYMASK 0x00FF /* default qualifier key mask */
#define SHIFT IECODE_UP_PREFIX
#define BADVALUE -1 /* error while parsing input line */
/*
* Macros to tell whether a character is printable or not, and
* whether it is not alphanumeric
*/
#define PRINTABLE(c) ((c)>=' '&&(c)<='~')
#define NOTPRINTABLE(c) ((c)<' '||(c)>'~')
#define NOTALPHANUM(c)\
((c)<'0'||((c)>'9'&&(c)<'A')||((c)>'Z'&&(c)<'a')||(c)>'z')
/*
* Create a new instance of a given structure type
*/
#define NEW(s,var) (var = (struct s *)New("var",sizeof(struct s)))
#define LINESIZE 132
static char InputLine[LINESIZE+1]; /* the line read from the file */
static char *CurPos; /* current character position in line */
static char *CurWord; /* pointer to begining of current word */
static char TerminationChar; /* character that ended the word */
static int LineCount = 0; /* number of lines read from the file */
#endif
struct HotKeyItem *KeyList = NULL; /* the list of key definitions so far */
struct HotKey *KeyArray = NULL; /* the sorted array of key definitions */
int KeyCount = 0; /* the number of key definitions */
#define KEYARRAYSIZE (KeyCount*sizeof(struct HotKey))
#ifndef NO_FILE
static FILE *InFile = NULL; /* the input file */
#define ERROR _OSERR /* the system's error variable */
extern int ERROR;
/*
* This structure maps a character string to a numeric value. It is used
* for mapping key names to keyboard scan codes and key action names to
* action numbers.
*/
struct Definition
{
char *Name;
UBYTE Code;
};
/*
* Qualifier[] maps the names of the qualifier keys to their corresponding
* bit positions within the ie_Qualifier field of an InputEvent. This List
* is sorted by name. Note that LCOMMAND is equivalent to LAMIGA, etc.
* Note also that there are some compound qualifier names, such as SHIFT.
* These are expanded into more than one key definition.
*
* See devices/inputevent.h for more details on qualifier values.
*/
static struct Definition Qualifier[] =
{
{"ALT",20},
{"AMIGA",22},
{"CAPSLOCK",2},
{"CONTROL",3},
{"INTERRUPT",10},
{"KEYUP",31},
{"LALT",4},
{"LAMIGA",6},
{"LBUTTON",14},
{"LCOMMAND",6},
{"LSHIFT",0},
{"MBUTTON",12},
{"MULTIBROADCAST",11},
{"NUMERICPAD",8},
{"RALT",5},
{"RAMIGA",7},
{"RBUTTON",13},
{"RCOMMAND",7},
{"RELATIVEMOUSE",15},
{"REPEAT",9},
{"RSHIFT",1},
{"SHIFT",16},
};
#define MAXQUALIFIER (sizeof(Qualifier)/sizeof(struct Definition))
/*
* AsciiToKeyCode[] maps ASCII characters to keyboard scan-codes. This array
* is in ASCII order. SHIFT indicates that one of the shift keys must be
* held down together with the correct key in order to produce that ASCII
* character. Note, however, that upper- and lower-case letters both are
* mapped to un-shifted keys.
*/
static UBYTE AsciiToKeyCode[] =
{
0x01 | SHIFT, /* ! */
0x2A | SHIFT, /* " */
0x03 | SHIFT, /* # */
0x04 | SHIFT, /* $ */
0x05 | SHIFT, /* % */
0x07 | SHIFT, /* & */
0x2A, /* ' */
0x09 | SHIFT, /* ( */
0x0A | SHIFT, /* ) */
0x08 | SHIFT, /* * */
0x0C | SHIFT, /* + */
0x38, /* , */
0x0B, /* - */
0x39, /* . */
0x3A, /* / */
0x0A, /* 0 */
0x01, /* 1 */
0x02, /* 2 */
0x03, /* 3 */
0x04, /* 4 */
0x05, /* 5 */
0x06, /* 6 */
0x07, /* 7 */
0x08, /* 8 */
0x09, /* 9 */
0x29 | SHIFT, /* : */
0x29, /* ; */
0x38 | SHIFT, /* < */
0x0C, /* = */
0x39 | SHIFT, /* > */
0x3A | SHIFT, /* ? */
0x02 | SHIFT, /* @ */
0x20, /* A */
0x35, /* B */
0x33, /* C */
0x22, /* D */
0x12, /* E */
0x23, /* F */
0x24, /* G */
0x25, /* H */
0x17, /* I */
0x26, /* J */
0x27, /* K */
0x28, /* L */
0x37, /* M */
0x36, /* N */
0x18, /* O */
0x19, /* P */
0x10, /* Q */
0x13, /* R */
0x21, /* S */
0x14, /* T */
0x16, /* U */
0x34, /* V */
0x11, /* W */
0x32, /* X */
0x15, /* Y */
0x31, /* Z */
0x1A, /* [ */
0x0D | SHIFT, /* \ */
0x1B, /* ] */
0x06 | SHIFT, /* ^ */
0x0B | SHIFT, /* _ */
0x00, /* ` */
0x20, /* a */
0x35, /* b */
0x33, /* c */
0x22, /* d */
0x12, /* e */
0x23, /* f */
0x24, /* g */
0x25, /* h */
0x17, /* i */
0x26, /* j */
0x27, /* k */
0x28, /* l */
0x37, /* m */
0x36, /* n */
0x18, /* o */
0x19, /* p */
0x10, /* q */
0x13, /* r */
0x21, /* s */
0x14, /* t */
0x16, /* u */
0x34, /* v */
0x11, /* w */
0x32, /* x */
0x15, /* y */
0x31, /* z */
0x1A | SHIFT, /* { */
0x0D | SHIFT, /* | */
0x1B | SHIFT, /* } */
0x00 | SHIFT, /* ~ */
};
#define MAXASCII sizeof(AsciiToKeyCode)
/*
* Key[] maps key names to their keyboard scan-codes. This array is sorted
* by name. SHIFT means that a SHIFT key must be held down in addition to
* the indicated key. Some keys have more than one name (e.g., ESCAPE is
* equivalent to ESC). Note that pressing a qualifier key also can be
* detected.
*/
static struct Definition Key[] =
{
{"BACKSPACE",0x41},
{"BS", 0x41},
{"CAPSLOCKKEY",0x62},
{"COLON",0x29 | SHIFT},
{"COMMA",0x38},
{"CONTROLKEY",0x63},
{"DASH",0x0B},
{"DEL",0x46},
{"DELETE",0x46},
{"DOT",0x3C},
{"DOWNARROW",0x4D},
{"ENTER",0x42},
{"ESC",0x45},
{"ESCAPE",0x45},
{"F1",0x50},
{"F10",0x59},
{"F2",0x51},
{"F3",0x52},
{"F4",0x53},
{"F5",0x54},
{"F6",0x55},
{"F7",0x56},
{"F8",0x57},
{"F9",0x58},
{"HELP",0x5F},
{"KP0",0x0F},
{"KP1",0x1D},
{"KP2",0x1E},
{"KP3",0x1F},
{"KP4",0x2D},
{"KP5",0x2E},
{"KP6",0x2F},
{"KP7",0x3D},
{"KP8",0x3E},
{"KP9",0x3F},
{"LALTKEY",0x64},
{"LAMIGAKEY",0x66},
{"LCOMMANDKEY",0x66},
{"LEFTARROW",0x4F},
{"LSHIFTKEY",0x60},
{"MINUS",0x4A},
{"RALTKEY",0x65},
{"RAMIGAKEY",0x67},
{"RCOMMANDKEY",0x67},
{"RETURN",0x44},
{"RIGHTARROW",0x4E},
{"RSHIFTKEY",0x61},
{"SPACE",0x40},
{"TAB",0x42},
{"UPARROW",0x4C},
};
#define MAXKEY (sizeof(Key)/sizeof(struct Definition))
/*
* Action[] maps key action names to their action numbers (used by the
* input handler to perform the action when the key is pressed). This array
* is sorted by name.
*/
static struct Definition Action[] =
{
{"BACK-WINDOW-TO-FRONT", BACKTOFRONT},
{"CLOSE-WINDOW", CLOSETHEWINDOW},
{"FRONT-WINDOW-TO-BACK", FRONTTOBACK},
{"ICON-TO-WINDOW", ICONTOWINDOW},
{"NEXT-WINDOW", ACTIVATENEXT},
{"PREVIOUS-WINDOW", ACTIVATEPREVIOUS},
{"SCREEN-TO-BACK", SCREENTOBACK},
{"SCREEN-TO-FRONT", SCREENTOFRONT},
{"SELECT-NEXT-ICON", SELECTNEXTICON},
{"WINDOW-TO-BACK", WINDOWTOBACK},
{"WINDOW-TO-FRONT", WINDOWTOFRONT},
{"WINDOW-TO-ICON", WINDOWTOICON},
};
#define MAXACTION (sizeof(Action)/sizeof(struct Definition))
#endif
/*
* Some shorthand macros used to define the default key layout
*/
#define RAMIGA IEQUALIFIER_RCOMMAND
#define RSHIFT IEQUALIFIER_RSHIFT
#define UPARROW 0x4C
#define DOWNARROW 0x4D
#define RIGHTARROW 0x4E
#define LEFTARROW 0x4F
#define BSKEY 0x41
#define TABKEY 0x42
#define RETURNKEY 0x44
#define DELETEKEY 0x46
#define HOTKEY(q,c,a) {{c,0,q},{0xFF,a,RAMIGA|RSHIFT}}
/*
* DefaultKey[] maps the default key layout. This array is sorted by
* KeyCode value. Change this array to change the default key bindings.
*/
static struct HotKey DefaultKey[] =
{
HOTKEY( RAMIGA, BSKEY, ICONTOWINDOW),
HOTKEY( RAMIGA, TABKEY, SELECTNEXTICON),
HOTKEY( RAMIGA, RETURNKEY, WINDOWTOICON),
HOTKEY( RAMIGA, DELETEKEY, CLOSETHEWINDOW),
HOTKEY( RAMIGA, UPARROW, WINDOWTOFRONT),
HOTKEY( RSHIFT | RAMIGA, UPARROW, SCREENTOFRONT),
HOTKEY( RAMIGA, DOWNARROW, WINDOWTOBACK),
HOTKEY( RSHIFT | RAMIGA, DOWNARROW, SCREENTOBACK),
HOTKEY( RAMIGA, RIGHTARROW, ACTIVATENEXT),
HOTKEY( RSHIFT | RAMIGA, RIGHTARROW, FRONTTOBACK),
HOTKEY( RAMIGA, LEFTARROW, ACTIVATEPREVIOUS),
HOTKEY( RSHIFT | RAMIGA, LEFTARROW, BACKTOFRONT),
};
#define DEFAULTSIZE (sizeof(DefaultKey)/sizeof(struct HotKey))
#ifndef NO_FILE
/*
* Error()
*
* Print an error message and the line number where the error occured.
* Return the error value.
*/
static int Error(s,x1,x2,x3)
char *s, *x1,*x2,*x3;
{
printf("Line %2d: ",LineCount);
printf(s,x1,x2,x3);
printf("\n");
return(BADVALUE);
}
/*
* GetNextWord()
*
* Isolate the next word in the line read from the file.
* If we are not at the end of the line, then
* skip over leading spaces,
* set CurWord to point to the beginning of the word,
* while we are not at the end of the word,
* check if the current character is a word delimiter:
* if it is a space or a tab,
* skip additional spaces or tabs,
* set the terminator character,
* and end the word.
* (At this point, CurPos will be pointing to the "real" delimiter,
* or to the beginning of the next word, if the delimiter really was
* a space).
* if it was a NULL, convert it to a new-line.
* if it was a dash, comma, colon or new-line,
* save the termination character for later,
* replace the charactger with a NULL so that CurWord will end at
* the end of the word,
* and stop looking for more of the word.
* otherwise
* if we're still looking for the end of the word (i.e., we have not
* ended, it by hitting a space),
* if its unprintable or the current word is more than one character
* long and the current character is not alphanumeric,
* then record the bad character and end the word
* go on to the next character (i.e., add the current one to the word)
*/
static void GetNextWord()
{
short NotDone = TRUE;
char c;
if (TerminationChar != '\n')
{
while (*CurPos == ' ' || *CurPos == '\t') CurPos++;
CurWord = CurPos;
while (NotDone)
{
if (*CurPos == ' ' || *CurPos == '\t')
{
*CurPos = '\0';
while (*(++CurPos) == ' ' || *CurPos == '\t');
TerminationChar = ' ';
NotDone = FALSE;
}
switch(c = *CurPos)
{
case '\0':
c = *CurPos = '\n';
case '-':
case ',':
case ':':
case '\n':
TerminationChar = c;
*CurPos++ = '\0';
NotDone = FALSE;
break;
default:
if (NotDone)
{
if (NOTPRINTABLE(c) || (CurPos != CurWord && NOTALPHANUM(c)))
{
TerminationChar = c;
NotDone = FALSE;
}
CurPos++;
}
break;
}
}
}
}
/*
* FindWord()
*
* Search the KeyWord array (containing Count entries) for an entry with
* Name equal to theWord. Return the corresponding Code value, or BADVALUE
* if theWord does not appear in the KeyWord array.
*
* KeyWord[] must be sorted by name, since we use a binary search to find
* theWord witin it.
*/
static int FindWord(theWord,KeyWord,Count)
char *theWord;
struct Definition KeyWord[];
int Count;
{
int value = BADVALUE;
register short Min,Max, Num;
register int comp;
Max = Count; Min = -1;
while ((Num = (Min + Max) >> 1) != Min && value == BADVALUE)
{
comp = stricmp(theWord,KeyWord[Num].Name);
if (comp < 0) Max = Num; else if (comp > 0) Min = Num;
else value = KeyWord[Num].Code;
}
return(value);
}
/*
* FindQualifier()
*
* Find a qualifier name in the Qualifier[] array.
*/
#define FindQualifier(w) FindWord(w,Qualifier,MAXQUALIFIER)
/*
* FindKeyCode()
*
* Find the scan-code for the given key name. If the key name is a single
* ASCII character, use the AsciiToKeyCode array to look up the scan-code
* directly, otherwise use FindWord() to search the Key[] array.
*/
static int FindKeyCode(theWord)
char *theWord;
{
int value = BADVALUE;
if (strlen(theWord) == 1)
{
if (PRINTABLE(*theWord)) value = AsciiToKeyCode[*theWord-'!'];
} else {
value = FindWord(theWord,Key,MAXKEY);
}
return(value);
}
/*
* GetKeyCode()
*
* Parse a set of qualifiers and a key name and return the KeyCode longword
* that describes the designated key. SHIFT, AMIGA, and ALT flags are
* used to indicate when more than one key is designated. Return BADVALUE
* if there is an error parsing the line.
*
* Get the next word on the line, and check the termination character.
* Qualifiers end with dashes, commas, or spaces; key-names end with a colon.
* Try to find the qualifier or key-name in the proper list, and give an error
* if it can not be found, or if the name is null. For a qualifier, set its
* flag bit in the KeyCode longword. For key-names, set the scan-code and
* the set the SHIFT bit in the qualifier flag bits if necessary.
* If the end of the line is reached, display an error. If some other
* delimiter was found, then display an error (making unprintable characters
* printable).
*
* Once a key-name is found, stop looking for more words.
*/
static void GetKeyCode(theKey)
long *theKey;
{
short NotDone = TRUE;
int value;
*theKey = 0;
while (NotDone)
{
GetNextWord();
switch(TerminationChar)
{
case '-':
case ',':
case ' ':
if (strlen(CurWord))
{
value = FindQualifier(CurWord);
if (value > BADVALUE)
*theKey |= (1 << value);
else
*theKey = Error("Unrecognized key qualifier '%s'",CurWord);
} else {
*theKey = Error("Missing qualifier keyword");
}
break;
case ':':
if (strlen(CurWord))
{
value = FindKeyCode(CurWord);
if (value > BADVALUE)
{
*theKey |= ((value & (~SHIFT)) << 24) |
((value & SHIFT) << 9);
} else {
*theKey = Error("Unrecognized key name '%s'",CurWord);
}
} else {
*theKey = Error("Key name not specified");
}
NotDone = FALSE;
break;
case '\n':
*theKey = Error("Key name ends prematurely");
NotDone = FALSE;
break;
default:
if ((TerminationChar & 0x7F) >= ' ')
*theKey = Error("Illegal delimiter character '%c'",
(char)TerminationChar);
else
*theKey = Error("Illegal delimiter character '^%c'",
(char)((TerminationChar & 0x7F) + '@'));
break;
}
}
}
/*
* GetKeyAction()
*
* Parse the rest of the input line for a key-action keyword. First, remove
* leading and training blanks, and replace the final new-line with a NULL.
* Look up the remainder of the line (if any) in the Action[] array, and
* if it is not found, report the error.
*/
static void GetKeyAction(theAction)
short *theAction;
{
*theAction = BADVALUE;
while (*CurPos == ' ' || *CurPos == '\t') CurPos++;
CurWord = CurPos;
CurPos = CurPos + strlen(CurWord) - 1;
if (*CurPos == '\n') *CurPos-- = '\0';
while (*CurPos == ' ' || *CurPos == '\t') *CurPos-- = '\0';
if (*CurWord)
{
*theAction = FindWord(CurWord,Action,MAXACTION);
if (*theAction == BADVALUE) Error("Unrecognized action '%s'",CurWord);
} else {
Error("No action specified");
}
}
/*
* KeyCompare()
*
* Return a positive number if the first key is bigger than the second,
* zero if they are equal, and a negative number if the second key is
* bigger. This routine is used by mSort() to sort the keys.
*/
static int KeyCompare(key1,key2)
struct HotKeyItem *key1, *key2;
{
return(key1->hki_KeyCode - key2->hki_KeyCode);
}
/*
*
* KeyDispose()
*
* Remove a duplicate key definition and report the fact that a key is
* multiply defined (it takes a little work to get the qualifier and key
* names back out of the arrays). This routine is called by mSort() when
* it finds duplicate keys.
*/
static void KeyDispose(key)
struct HotKeyItem *key;
{
short i;
UBYTE code = key->hki_Code & 0x7F;
int KeyNotFound = TRUE;
long mask = 0xFFFFFFFF;
printf("Key ");
for (i=0; i<MAXQUALIFIER; i++)
if (key->hki_KeyCode & (1 << Qualifier[i].Code) & mask)
{
printf("%s-",Qualifier[i].Name);
mask &= ~(1 << Qualifier[i].Code);
}
for (i=0; i<MAXKEY && KeyNotFound; i++)
if (code == Key[i].Code)
{
printf("%s",Key[i].Name);
KeyNotFound = FALSE;
}
for (i=0; i<MAXASCII && KeyNotFound; i++)
{
if (code == AsciiToKeyCode[i])
{
printf("%c",i+'!');
KeyNotFound = FALSE;
}
}
printf(" multiply defined\n");
KeyCount--;
key->Next = key->Prev = NULL;
FreeMem(key,sizeof(*key));
}
/*
* GetKeyList()
*
* Read each line from the file (incrementing the line count as we go),
* and skip leading spaces and blank lines. Get the key code and key action
* specified on the line. If no error was found, add the key definition
* to the linked list of keys defined. If SHIFT, AMIGA, or ALT were specified,
* then add one key each for the left and right version of that qualifier.
*/
static void GetKeyList()
{
long theKey;
short theAction;
struct HotKeyItem *TempKey;
UWORD mask,multikeys;
extern char *fgets();
while (feof(InFile) == FALSE)
{
CurPos = fgets(InputLine,LINESIZE,InFile);
TerminationChar = '\0';
LineCount++;
while (*CurPos == ' ' || *CurPos == '\t') CurPos++;
if (CurPos != NULL && *CurPos != '\0' && *CurPos != '\n')
{
GetKeyCode(&theKey);
GetKeyAction(&theAction);
if (theKey != BADVALUE && theAction != BADVALUE)
{
multikeys = (theKey >> 15) & 0xFE;
multikeys |= multikeys << 1;
if (multikeys == 0) multikeys = 1;
for (mask=1; multikeys; mask<<=1,multikeys>>=1)
{
if (multikeys & 1)
{
NEW(HotKeyItem,TempKey);
TempKey->hki_KeyCode = theKey;
TempKey->hki_Flags = 0;
TempKey->hki_Qual |= mask >> 1;
TempKey->hki_KeyMask = 0xFFFFFFFF;
TempKey->hki_Action = theAction;
TempKey->Next = KeyList;
KeyList = TempKey;
KeyCount++;
}
}
}
}
}
}
/*
* SetKeyMasks()
*
* For each key scan-code, we OR together the qualifier masks for all the
* definitions for that scan-code and set the key Mask value for each
* key with that scan-code to the final ORed mask. That is, the Mask value
* indicates what qualifiers are important for determining when a key has
* been pressed (and distinguishing it from other definitions using the
* same scan-code but different qualifiers).
*/
static void SetKeyMasks()
{
struct HotKeyItem *CurKey = KeyList;
struct HotKeyItem *LastKey = CurKey;
UWORD Mask;
while (LastKey)
{
Mask = 0;
while (CurKey && CurKey->hki_Code == LastKey->hki_Code)
{
Mask |= CurKey->hki_Qual;
CurKey = CurKey->Next;
}
if (Mask == 0) Mask = KEYMASK;
do
{
LastKey->hki_Mask = Mask;
LastKey = LastKey->Next;
} while (LastKey != CurKey);
}
}
/*
* MakeKeyArray()
*
* If there are any keys defined, allocate enough space for the KeyArray
* that will contain the key definitions, then go through the list and
* copy the definitions into the array. Free each item from the list once it
* is copied. The array saves space (it does not need to contain pointers
* to next and previous items), and allows for easy implementation of a
* binary search on the array.
*/
static void MakeKeyArray()
{
struct HotKeyItem *TempKey;
short i;
if (KeyCount)
{
KeyArray = (struct HotKey *)New("KeyArray",KEYARRAYSIZE);
for (i=0; i<KeyCount; i++)
{
KeyArray[i].hk_KeyCode = KeyList->hki_KeyCode;
KeyArray[i].hk_KeyMask = KeyList->hki_KeyMask;
TempKey = KeyList; KeyList = KeyList->Next;
FreeMem(TempKey,sizeof(*TempKey));
}
}
}
#endif
/*
* MakeDefaultArray()
*
* Copy the DefaultKey[] array into a dynamically allocated array that can
* be passed to the input handler and still remain in memory even when the
* original process is unloaded.
*/
static void MakeDefaultArray()
{
short i;
KeyCount = DEFAULTSIZE;
KeyArray = (struct HotKey *)New("KeyArray",KEYARRAYSIZE);
for (i=0; i<KeyCount; i++)
{
KeyArray[i].hk_KeyCode = DefaultKey[i].hk_KeyCode;
KeyArray[i].hk_KeyMask = DefaultKey[i].hk_KeyMask;
}
}
/*
* GetKeyArray()
*
* If there is a command-line argument, then
* it must be a file name, so try to open it (error if there is a problem).
* Create the key definition list from the lines in the file.
* If there were no valid key definitions,
* say so,
* otherwise,
* sort the key list,
* set the key masks for each scan-code,
* make the key array from the sorted list.
* otherwise (there was no file name given, so)
* make the key array from the default key list.
*/
void GetKeyArray(argc,argv)
int argc;
char *argv[];
{
#ifndef NO_FILE
extern struct HotKeyItem *mSort();
if (argc > 1)
{
InFile = fopen(argv[1],"r");
if (InFile == NULL)
DoExit("Can't Open File '%s': Error %d",argv[1],ERROR);
GetKeyList();
if (KeyCount == 0)
{
DoExit("No valid key definitions found in file '%s'",argv[1]);
} else {
KeyList = mSort(KeyList,KeyCompare,KeyDispose);
SetKeyMasks();
MakeKeyArray();
}
} else
#endif
{
MakeDefaultArray();
}
}